//////////////////////////////////////////////////
// EASIM project
// easim.net.Synchronizer
// 6/6/2007 6:57 PM
// Cong Liu
// gzcong@gmail.com

// Copyright (C) 2007
// All rights reserved.
// Refer to LICENSE of JIST (Java In Simulation Time) for terms and conditions of use.

package easim.win;

import jist.runtime.JistAPI;
import jist.swans.Constants;

public class Synchronizer implements SynchronizerInterface, jist.runtime.JistAPI.DoNotRewrite
{
  
  private static SynEntity entity;
  private static boolean request;
  private static boolean pausing;
  private static int jobs;

  public static void start() {
    if (entity == null) {
      entity = new SynEntity();
      SynInterface synInterface = entity.getProxy();
      synInterface.start();
    }
  }

  public static void pause() {
    ++ jobs;
    //System.out.print("J+" + jobs + " ");
    request = true;
    synchronized (entity) {
      if (! pausing) {
        try {
          entity.wait();
        } catch (InterruptedException ex) {
        }
      }
    }
  }

  public static void resume() {
    -- jobs;
    //System.out.print("J-" + jobs + " ");
    if (jobs == 0) {
      request = false;
      synchronized (entity) {
        entity.notify();
      }
    }
  }

  public static interface SynInterface extends JistAPI.Proxiable
  {
    void start();
  }

  public static class SynEntity implements SynInterface
  {

    private long startRealTime = -1;
    private long startSimTime;

    private SynInterface proxy = (SynInterface)JistAPI.proxy(this, SynInterface.class);

    public SynInterface getProxy() {
      return proxy;
    }

    public synchronized void start() {
      if (startRealTime == -1) {
        startRealTime = System.currentTimeMillis() * Constants.MILLI_SECOND;
        startSimTime = JistAPI.getTime();
        pausing = false;
      }
      long curRealTime = System.currentTimeMillis() * Constants.MILLI_SECOND;
      long curSimTime = JistAPI.getTime();
      long pastRealTime = curRealTime - startRealTime;
      long pastSimTime = curSimTime - startSimTime;
      long pauseTime = (pastSimTime - pastRealTime) / Constants.MILLI_SECOND;
      if (pauseTime > 0) {
        try {
          wait(pauseTime);
        } catch (InterruptedException ex) {
        }
      }
      if (request) {
        pausing = true;
        notify();
        long pauseStartTime = System.currentTimeMillis();
        while (jobs > 0) {
          try {
            wait();
          } catch (InterruptedException ex) {
          }
        }
        long pauseEndTime = System.currentTimeMillis();
        startRealTime += (pauseEndTime - pauseStartTime) * Constants.MILLI_SECOND;
        pausing = false;
      }
      JistAPI.sleep(SYN_INTERVAL * Constants.MILLI_SECOND);
      proxy.start();
    }

  } // end class SynEntity

  /////////////////////
  // Test
  /*/

  public static void main(String[] args) {
    JistAPI.endAt(3 * Constants.SECOND);
    new Entity1().start();
    Synchronizer.start();
    new Test1().start();
  }

  public static class Test1 extends Thread
  {

    public synchronized void run() {
      try {
        sleep(1000);
        Synchronizer.pause();
        sleep(2000);
        Synchronizer.resume();
      } catch (InterruptedException ex) {
      }
    }

  } // end class Test1

  static class Entity1 implements JistAPI.Entity
  {

    public void start() {
      System.out.println(new java.util.Date() + "   " + JistAPI.getTime());
      JistAPI.sleep(100 * Constants.MILLI_SECOND);
      start();
    }

  } // end class Entity1

  /**/

}

